#include <iostream>
#include <stdio.h>
using namespace std;

#define MAXLENGTH   260
#define TESTSIZE    8 * 1024 * 1024

void MEM_DEL(BYTE *pData)                     
{								        
	if (pData != NULL)			        
	{							        
		delete[] pData;			        
		pData	=	NULL;               
	}							        
}


BOOL    RAMTest()
{
	MEMORYSTATUS    ms;
	SYSTEM_INFO     SysInfo;
	DWORD           dwPageSize      =   0;
	DWORD           dwPhyMEM        =   0;
	DWORD           dwAddr          =   0;
	DWORD           dwReadData      =   0;
	BOOL            bRet            =   TRUE;
	BYTE           *punMemBase      =   NULL;
	volatile DWORD *punMem          =   NULL;
	volatile DWORD *punEnd          =   NULL;
	int             nIdx            =   0;
	DWORD           dwPattern       =   0;
	int             nOffset         =   0;
	TCHAR           szMsg[MAXLENGTH];
	try{
		memset(&SysInfo,0,sizeof(SYSTEM_INFO));
		SysInfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
		GetSystemInfo(&SysInfo);
		dwPageSize  =   SysInfo.dwPageSize;


		ms.dwLength = sizeof(MEMORYSTATUS);
		GlobalMemoryStatus(&ms);
		dwPhyMEM    =   TESTSIZE;
		//dwPhyMEM	=	ms.dwAvailPhys * 0.8;
		printf("Total physical memory %d \n",ms.dwAvailPhys);
		printf("Test to access Physical memory %d \n",dwPhyMEM);

		for(nIdx = 0 ; nIdx < 4 ; nIdx++)
		{
			if(nIdx ==  0)
				dwPattern   =   0;
			if(nIdx ==  1)
				dwPattern   =   0xFFFFFFFF;
			if(nIdx ==  2)
				dwPattern   =   0xAAAAAAAA;
			if(nIdx ==  3)
				dwPattern   =   0x55555555;
			memset(szMsg,0,sizeof(szMsg));
			swprintf(szMsg,L"Start Test Pattern 0x%08X...\n",dwPattern);
			wprintf(szMsg);

			punMemBase  =   new BYTE[dwPhyMEM];
			if(punMemBase   ==  NULL)
			{
				printf("Can not allocate %d memory size.\n",dwPhyMEM);
				return FALSE;
			}
			punMem  =   (volatile DWORD *)punMemBase;
			punEnd  =   (volatile DWORD *)(punMemBase + dwPhyMEM);
			// 			MyFill((DWORD*)punMem,(DWORD*)punEnd,(DWORD)dwPattern,0);
			// 			bRet    =   MyVerify((DWORD*)punMem,(DWORD*)punEnd,(DWORD)dwPattern,0);

			memset(punMemBase,0,dwPhyMEM);
			for( ; punMem < punEnd ; ++punMem)
				*punMem =   dwPattern;

			punMem  =   (volatile DWORD *)punMemBase;
			punEnd  =   (volatile DWORD *)(punMemBase + dwPhyMEM);
			for( ; punMem < punEnd ; ++punMem)
			{
				if(*punMem  !=  dwPattern)
				{
					printf("Failed at: Address = 0x%08X \nOffset = 0x%08X\n", punMem,((BYTE*)punMem - punMemBase));
					printf("0x%08X != 0x%08X\n", *punMem,dwPattern);
					bRet    =   FALSE;
					break;
				}
			}

			// Free Phy Memory
			MEM_DEL(punMemBase);
		}
	} // End of nIdx for loop
	catch(...)
	{
		memset(szMsg,0,sizeof(szMsg));
		swprintf(szMsg,L"occur an error at 0x%08X \n",(unsigned int*)(punMem));
		wprintf(szMsg);
		MEM_DEL(punMemBase);
		return FALSE;
	}
	return TRUE;
}

BOOL VirtualMemTest()
{
	MEMORYSTATUS    ms;
	BOOL            bRet            =   FALSE;
	TCHAR          *pchVirtual      =   NULL;
	DWORD           dwVirtualSize   =   0;

	try{
		// Get Virtual Memory size
		memset(&ms,0,sizeof(MEMORYSTATUS));
		ms.dwLength     =   sizeof(MEMORYSTATUS);
		GlobalMemoryStatus(&ms);
		dwVirtualSize   =   ms.dwAvailVirtual;
		printf("Virtual Memory Size is %d\n",dwVirtualSize);

		// Allocate all Virtual Memory
		pchVirtual  = (TCHAR *)VirtualAlloc(NULL, 
			dwVirtualSize,
			MEM_RESERVE,
			PAGE_NOACCESS);
		if (pchVirtual == NULL)
			return FALSE;

		printf("Allocate All Virtual Memory Successful.\n");
		// Release all virtual memory
		bRet = VirtualFree(pchVirtual,0,MEM_RELEASE);
		if(!bRet)
			return FALSE;
		printf("Realse All Virtual Memory Successful.\n");
		  return TRUE;  
	}
	catch(...)
	{
		return FALSE;
	}
	
}

BOOL RAMTestLoop()
{
	for (int i = 0;i<256;i++)
	{
		cout<<"ram memtest"<<i<<endl;
		if(!RAMTest())
			return FALSE;
	}
	return TRUE;
}

BOOL VirtualMemTestLoop()
{
	for (int i = 0;i<256;i++)
	{
		cout<<"virtual memtest"<<i<<endl;
		if(!VirtualMemTest())
			return FALSE;
	}
	return TRUE;
}
